{"componentChunkName":"component---src-templates-blog-post-js","path":"/typescript/typescript-redux/","result":{"data":{"site":{"siteMetadata":{"title":"Tory","author":"[Tory]","siteUrl":"https://gatsby-starter-bee.netlify.com","comment":{"disqusShortName":"","utterances":"JaeYeopHan/gatsby-starter-bee"},"sponsor":{"buyMeACoffeeId":"jbee"}}},"markdownRemark":{"id":"158b2cc0-7fb1-5f53-a6d8-a877eab8dd4a","excerpt":"Jump into Redux with typescript 리덕스를 typescript로 작성해보자!\n모든 내용은 redux 홈페이지를 참고했다. 매우 친절하게 설명되어 있으니 읽어보는 것을 왕왕 추천함! 📒 What we’ll learn? typescript로 Redux를 작성하는 표준 패턴! Redux 로직에서 올바르게 타입을 지정하는 방법 🧠 PREREQUISITES 당연하지만 이 챕터를 학습하기 위해서는 ts 문법과 용어를 알고 있어야 한다. 특히 ts의 generic과 utility…","html":"<h1 id=\"jump-into-redux-with-typescript\" style=\"position:relative;\"><a href=\"#jump-into-redux-with-typescript\" aria-label=\"jump into redux with typescript permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Jump into Redux with typescript</h1>\n<p>리덕스를 typescript로 작성해보자!\n모든 내용은 <a href=\"https://redux.js.org/usage/usage-with-typescript\">redux 홈페이지</a>를 참고했다. 매우 친절하게 설명되어 있으니 읽어보는 것을 왕왕 추천함!</p>\n<p>📒 What we’ll learn?</p>\n<ul>\n<li>typescript로 Redux를 작성하는 표준 패턴!</li>\n<li>Redux 로직에서 올바르게 타입을 지정하는 방법</li>\n</ul>\n<p>🧠 PREREQUISITES</p>\n<ul>\n<li>당연하지만 이 챕터를 학습하기 위해서는 ts 문법과 용어를 알고 있어야 한다.</li>\n<li>특히 ts의 generic과 utility type에 대해 알고 있어야 한다.</li>\n<li>리액트 훅은 필수!</li>\n</ul>\n<h2 id=\"overview\" style=\"position:relative;\"><a href=\"#overview\" aria-label=\"overview permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Overview</h2>\n<p>리덕스를 타입스크립트와 함께 사용했을 때 얻을 수 있는 장점을 아래와 같다.</p>\n<ol>\n<li>reducer, state, action creator, UI 컴포넌트 까지 전반적으로 타입오류에 대한 걱정을 줄일 수 있다.</li>\n<li>리펙토링이 쉬워진다.</li>\n<li>A superior developer experience in a team environment (무슨 의미일지 실제로 팀에 소속되어 프로젝트 경험을 해봐야 알 것 같다.)</li>\n</ol>\n<p>그러나… 언제나 트레이드 오프는 있는법! 타입에 대한 고민, 코드량 증가, 타입 로직에 의한 코드 복잡도 증가 등 typescript를 적용하는 것은 생각보다 많은 비용이 소모된다. 따라서 프로젝트의 성격에 맞추어 ts를 적용할지 고민할 필요는 있다.</p>\n<p>그럼에도 불구하고, Redux에서는 typescript를 절적하게 사용하면 분명히 큰 이점이 있다며 권장하고 있기에 이제 본격적으로 Redux 공식홈페이지에서 제공하는 typescript 표준 패턴에 대해 알아보자!</p>\n<h2 id=\"standard-redux-toolkit-project-setup-with-typescript\" style=\"position:relative;\"><a href=\"#standard-redux-toolkit-project-setup-with-typescript\" aria-label=\"standard redux toolkit project setup with typescript permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Standard Redux Toolkit Project Setup with TypeScript</h2>\n<p>Redux Toolkit(이하 RTK)은 기존 reducer, actionType, actionCreator 등등을 반드시 작성해야 했던 Redux의 복잡한 로직을 간편하게 만들어주며 이는 Redux 로직의 표준으로 자리잡았다.</p>\n<p>Redux Toolkit은 이미 TypeScript로 작성되어있다. 따라서 단순하게 라이브러리를 가져다 사용하는 것을 넘어 타입에 대한 hint를 제공하고 있기 때문에 이를 참조하여 작성해 보자. 보다 쉬운 개발 경험을 제공할 것이니…!</p>\n<p>react-redux 또한 <code class=\"language-text\">@types/react-redux</code>라는 별도의 라이브러리로 타입에 대한 정의를 제공하고 있다. react-redux 7.2.3 버전부터 dependency로 함께 설치된다고 하니 그 이하 버전을 사용할 경우에는 수동으로 설치할 필요가 있다.</p>\n<h3 id=\"define-root-state-and-dispatch-types\" style=\"position:relative;\"><a href=\"#define-root-state-and-dispatch-types\" aria-label=\"define root state and dispatch types permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Define Root State and Dispatch Types</h3>\n<p>useSelector를 사용하면서 오류가 발생했다.</p>\n<div class=\"gatsby-highlight\" data-language=\"ts\"><pre class=\"language-ts\"><code class=\"language-ts\"><span class=\"token keyword\">const</span> <span class=\"token builtin\">number</span> <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span>state <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<div style=\"text-align:center\">\n    <span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 641px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 18.333333333333336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAEABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABygQD/8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQABBQJ//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAEP/aAAgBAQAGPwJ//8QAFxAAAwEAAAAAAAAAAAAAAAAAAAEhEf/aAAgBAQABPyEyjjP/2gAMAwEAAgADAAAAEAPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAICAwAAAAAAAAAAAAAAAQARITFBUYH/2gAIAQEAAT8QApc77Y8CnsuoLP/Z'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"useSelecto 에러1\" title=\"useSelecto 에러1\" src=\"/static/da6e6667314e233abf0fbdb5b447b567/4b9ef/errorUseSelector_01.jpg\" srcset=\"/static/da6e6667314e233abf0fbdb5b447b567/f93b5/errorUseSelector_01.jpg 300w,\n/static/da6e6667314e233abf0fbdb5b447b567/b4294/errorUseSelector_01.jpg 600w,\n/static/da6e6667314e233abf0fbdb5b447b567/4b9ef/errorUseSelector_01.jpg 641w\" sizes=\"(max-width: 641px) 100vw, 641px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n</div>\n<p>Property ‘counter’가 type DefaultRootState에 존재하지 않는다고 한다.</p>\n<p>이때 useSelector의 hint를 확인해 보자.</p>\n<div style=\"text-align:center\">\n    <span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1200px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 27.333333333333332%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABywSD/8QAFRABAQAAAAAAAAAAAAAAAAAAARD/2gAIAQEAAQUCL//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAABD/2gAIAQEABj8Cf//EABkQAAEFAAAAAAAAAAAAAAAAAAEAEBEhUf/aAAgBAQABPyEqRjG//9oADAMBAAIAAwAAABCAD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQEAAwEAAAAAAAAAAAAAAAEAESExUf/aAAgBAQABPxBEDl37IRReF//Z'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"useSelecto 에러2\" title=\"useSelecto 에러2\" src=\"/static/0caf0c91f731f6023ad1527235c3fd46/e5166/errorUseSelector_02.jpg\" srcset=\"/static/0caf0c91f731f6023ad1527235c3fd46/f93b5/errorUseSelector_02.jpg 300w,\n/static/0caf0c91f731f6023ad1527235c3fd46/b4294/errorUseSelector_02.jpg 600w,\n/static/0caf0c91f731f6023ad1527235c3fd46/e5166/errorUseSelector_02.jpg 1200w,\n/static/0caf0c91f731f6023ad1527235c3fd46/0c02e/errorUseSelector_02.jpg 1206w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n</div>\n첫번째 매개변수로 입력되는 selector의 경우 state라는 매개변수를 콜백함수를 입력해야 하는데, 이때 state의 type이 DefaultRootState라고 되어있다. 이는 제네릭 문법으로, 위 이미지의 `useSelector<defaultrootstate, any=\"\">`부분을 참고하면 useSelector의 제네릭으로 DefaultRootState를 지정하였으며, 함수 내부에서 state가 그 타입을 받고 있음을 확인할 수 있다.</defaultrootstate,>\n<blockquote>\n<p>참고: generic이란? 타입이 string, number처럼 고정된 타입이 아니라 호출이 될 때 경우에 따라 타입이 바뀌어야 하면 위와 같이 제네릭을 문법을 사용하여 호출시에 type을 설정한다.\n(예제로 queue같은 경우 string Queue, number Queue 다양하게 사용될 수 있으며 제네릭을 사용하면 코드량을 줄일 수 있다.)</p>\n</blockquote>\n<div style=\"text-align:center\">\n    <span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1185px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 28.333333333333332%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAcuoQD//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAQ/9oACAEBAAY/An//xAAXEAEAAwAAAAAAAAAAAAAAAAABABAR/9oACAEBAAE/IR0iV//aAAwDAQACAAMAAAAQh8//xAAWEQADAAAAAAAAAAAAAAAAAAAQESH/2gAIAQMBAT8QUH//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAYEAEAAwEAAAAAAAAAAAAAAAABABExkf/aAAgBAQABPxBNGyUbXIBP/9k='); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"useSelector 에러3\" title=\"useSelector 에러3\" src=\"/static/6013a9a41d8e8ba2b4af96b68697fd35/abaab/errorUseSelector_03.jpg\" srcset=\"/static/6013a9a41d8e8ba2b4af96b68697fd35/f93b5/errorUseSelector_03.jpg 300w,\n/static/6013a9a41d8e8ba2b4af96b68697fd35/b4294/errorUseSelector_03.jpg 600w,\n/static/6013a9a41d8e8ba2b4af96b68697fd35/abaab/errorUseSelector_03.jpg 1185w\" sizes=\"(max-width: 1185px) 100vw, 1185px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n</div>\n심지어 hint를 조금 내려보면 어떻게 사용해야하는지도 알려준다.\n<p><a href=\"https://redux.js.org/usage/usage-with-typescript#define-root-state-and-dispatch-types\">공식문서</a>에도 자세하게 나와있으니 참고하길 바라며 아래와 같이 타입을 지정하여 문제를 해결하였다.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// index.tsx</span>\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">configureStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  reducer<span class=\"token operator\">:</span> rootReducer<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> type RootState <span class=\"token operator\">=</span> ReturnType<span class=\"token operator\">&lt;</span><span class=\"token keyword\">typeof</span> store<span class=\"token punctuation\">.</span>getState<span class=\"token operator\">></span><span class=\"token punctuation\">;</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// CounterContainer.tsx</span>\n<span class=\"token keyword\">const</span> useAppSelector<span class=\"token operator\">:</span> TypedUseSelectorHook<span class=\"token operator\">&lt;</span>RootState<span class=\"token operator\">></span> <span class=\"token operator\">=</span> useSelector\n\n<span class=\"token keyword\">function</span> <span class=\"token function\">CounterContainer</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// const number = useSelector&lt;RootState>(state => state.counter);</span>\n  <span class=\"token keyword\">const</span> number <span class=\"token operator\">=</span> <span class=\"token function\">useAppSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>","frontmatter":{"title":"typescript-redux","date":"August 29, 2021"}}},"pageContext":{"slug":"/typescript/typescript-redux/","previous":{"fields":{"slug":"/typescript/typescript-react/"},"frontmatter":{"title":"typescript-react","category":"typescript","draft":false}},"next":{"fields":{"slug":"/react/router/"},"frontmatter":{"title":"router","category":"react","draft":false}}}},"staticQueryHashes":["3128451518","521680639"]}